//
// Created by zhaog on 11/04/17.
//

#include <Poco/File.h>
#include <fstream>
#include <Poco/Stopwatch.h>
#include "general_img_req_handler.h"
#include "Poco/Net/HTTPServerResponse.h"
#include "Poco/StreamCopier.h"
#include "Poco/JSON/Parser.h"
#include "pack_meta_svr_api.h"
#include "img_svr_main.h"
#include "pack_pic_store_api.h"

using std::string;
namespace img_svr{

    void GeneralImgReqHandler::handleRequestImpl(HTTPServerRequest &request, HTTPServerResponse &response) {
        Poco::Stopwatch sw;
        sw.start();
        string req_body;
        string res_body;
        set<meta::MetaStruct> metas;
        Poco::StreamCopier::copyToString(request.stream(),req_body);
        string err;
        if(ParseReq(req_body,err)){
            ServiceLog.error("Err: action:get_general_img, parse request json error:%s",err);
            ErrReqLog.error("%s",req_body);
            res_body="request error:";
            res_body.append(err);
            response.setStatus(Poco::Net::HTTPResponse::HTTP_BAD_REQUEST);
            goto send;
        }
        _res_struct.staff_id="dw_zhaogang1";
        _res_struct.version="v1.0";
        ServiceLog.information("Request: action:get_general_img, staff_id:%s, version:%s, busi:%s, sub_req_count:%lu",_req_struct.staff_id,\
_req_struct.version,_req_struct.my_busi,_req_struct.req_body.size());
        for(vector<GeneralImgReqBodyStruct>::iterator it=_req_struct.req_body.begin();it!=_req_struct.req_body.end();it++){
            ServiceLog.information(" [req_id:%d, uid:%s, busi_type:%s, beg_time:%s, end_time:%s ]",it->req_id,it->uid,it->busi_type,it->beg_time,it->end_time);
        }
        printf("before get metas:%d\n",(int)sw.elapsed()/1000);
        GetRecentMetas(metas);
        printf("after get metas:%d\n",(int)sw.elapsed()/1000);
        if(metas.size()==0){
            response.setStatus(Poco::Net::HTTPResponse::HTTP_NOT_FOUND);
            res_body="no images";
            goto send;
        }else{
            vector<pic_store_api::ImgStruct> imgs;
            ShiftMetaToImgStruct(metas,imgs);
            printf("before get Imgs:%d\n",(int)sw.elapsed()/1000);
            if(GetImages(imgs)<=0){
                DownloadLog.error("Err:cannot download image,uid:%s");
                response.setStatus(Poco::Net::HTTPResponse::HTTP_NOT_FOUND);
                res_body="no images";
                goto send;
            }
            printf("after get Imgs:%d\n",(int)sw.elapsed()/1000);
            WriteFileData(imgs);
            printf("before send :%d\n",(int)sw.elapsed()/1000);
            PackResJson(res_body);
            response.setStatus(Poco::Net::HTTPResponse::HTTP_OK);
            printf("after send :%d\n",(int)sw.elapsed()/1000);
        }
        send:
        //printf("%s\n",res_body.c_str());
        response.setContentLength(res_body.size());
        response.sendBuffer(res_body.c_str(),res_body.size());

        ServiceLog.information("Response: action:get_general_img, version:%s, sub_res_count:%lu",_res_struct.version,_res_struct.res_body.size());
        for(vector<GenneralImgResBodyStruct>::iterator it=_res_struct.res_body.begin();it!=_res_struct.res_body.end();it++){
            ServiceLog.information(" [res_id:%d, count:%d ]",it->res_id,it->count);
        }
    }
    int GeneralImgReqHandler::GetRecentMetas(set<meta::MetaStruct> &metas) {
        Poco::ThreadPool thread_pool(1,(int)_req_struct.req_body.size());
        vector<SharedPtr<Poco::Event> > evs;
        vector<SharedPtr<PackMetaSvrApiGetGeneralMeta> > apis;
        vector<SharedPtr<set<meta::MetaStruct> > > metass;
        for(vector<GeneralImgReqBodyStruct>::iterator it=_req_struct.req_body.begin();it!=_req_struct.req_body.end();it++) {
            SharedPtr<set<meta::MetaStruct> > meta=new set<meta::MetaStruct>;
            metass.push_back(meta);
            SharedPtr<Poco::Event> ev=new Poco::Event;
            evs.push_back(ev);
            SharedPtr<PackMetaSvrApiGetGeneralMeta> api=new PackMetaSvrApiGetGeneralMeta(*ev,*meta,it->busi_type,it->uid,it->beg_time,it->end_time,"dw_zhaogang1");
            apis.push_back(api);
            thread_pool.start(*api);
        }
        for(vector<SharedPtr<Poco::Event> >::iterator it=evs.begin();it!=evs.end();it++){
            (*it)->wait();
        }
        for(vector<SharedPtr<set<meta::MetaStruct> > >::iterator it=metass.begin();it!=metass.end();it++){
            for(set<meta::MetaStruct>::iterator meta_it=(*it)->begin();meta_it!=(*it)->end();meta_it++){
                metas.insert(*meta_it);
            }
        }
        return 0;
    }
    int GeneralImgReqHandler::ParseReq(string &req_json, string &err) {
        if(req_json.size()==0){
            err="no request body";
            return -1;
        }
        Poco::JSON::Parser parser;
        Poco::Dynamic::Var result;
        Poco::JSON::Object::Ptr pObj;
        Poco::JSON::Array::Ptr pArr;

        Poco::Dynamic::Var ret;

        try{
            result=parser.parse(req_json);
        }catch(Poco::Exception &exc){
            err="json format error";
            return -1;
        }
        pObj=result.extract<Poco::JSON::Object::Ptr>();
        ret=pObj->get("staff_id");
        if(ret.isEmpty()) {
            err="no staff_id";
            return -1;
        }
        try{
            _req_struct.staff_id=ret.convert<std::string>();
        }catch(Poco::Exception &exc){
            err="staff_id format error";
            return -1;
        }
        ret=pObj->get("version");
        if(!ret.isEmpty()) {
            try {
                _req_struct.version = ret.convert<std::string>();
            } catch (Poco::Exception &exc) {

                return -1;
            }
        }

        ret=pObj->get("my_busi");
        if(!ret.isEmpty()) {
            try {
                _req_struct.my_busi = ret.convert<std::string>();
            } catch (Poco::Exception &exc) {

                return -1;
            }
        }

        pArr=pObj->getArray("body");
        if(!pArr){
            err="no request body";
            return -1;
        }

        for(Poco::JSON::Array::ConstIterator it=pArr->begin();it!=pArr->end();it++){
            pObj=it->extract<Poco::JSON::Object::Ptr>();
            GeneralImgReqBodyStruct req_body;
            ret=pObj->get("req_id");
            if(ret.isEmpty()){
                err="no req_id";
                return -1;
            }
            try{
                req_body.req_id=ret.convert<int>();
            }catch(Poco::Exception &exc){
                err="req_id format error";
                return -1;
            }
            ret=pObj->get("busi_type");
            if(ret.isEmpty()){
                err="no busi_type";
                return -1;
            }
            try{
                req_body.busi_type=ret.convert<std::string>();
            }catch(Poco::Exception &exc){
                err="busi_type format error";
                return -1;
            }
            ret=pObj->get("uid");
            if(ret.isEmpty()){
                err="no uid";
                return -1;
            }
            try{
                req_body.uid=ret.convert<std::string>();
            }catch(Poco::Exception &exc){
                err="uid format error";
                return -1;
            }
            ret=pObj->get("beg_time");
            if(ret.isEmpty()){
                err="no beg_time";
                return -1;
            }
            try{
                req_body.beg_time=ret.convert<string>();
            }catch(Poco::Exception &exc){
                err="beg_time format error";
                return -1;
            }
            ret=pObj->get("end_time");
            if(ret.isEmpty()){
                err="no end_time";
                return -1;
            }
            try{
                req_body.end_time=ret.convert<string>();
            }catch(Poco::Exception &exc){
                err="beg_time format error";
                return -1;
            }
            ret=pObj->get("label");
            if(ret.isEmpty()){
                req_body.label="all";
            }else {
                try {
                    req_body.label = ret.convert<string>();
                } catch (Poco::Exception &exc) {
                    err = "label format error";
                    return -1;
                }
            }
            _req_struct.req_body.push_back(req_body);
        }
        return 0;
    }
    int GeneralImgReqHandler::ShiftMetaToImgStruct(set<meta::MetaStruct> &metas,vector<pic_store_api::ImgStruct> &imgs) {
        for(set<meta::MetaStruct>::iterator it=metas.begin();it!=metas.end();it++){
            pic_store_api::ImgStruct img;
            img.uid=common::String::IntToString<int64_t >(it->uid);
            img.label=it->label_value;
            img.snapshot_time=it->snapshot_time;
            size_t pos=it->image_addr.rfind("/");
            if(pos==string::npos)
                continue;
            img.img_name=it->image_addr.substr(pos+1,it->image_addr.size()-pos-1);
            imgs.push_back(img);
        }
        return (int)imgs.size();
    }

    void GeneralImgReqHandler::WriteFileData(const vector<pic_store_api::ImgStruct> &imgs) {
        string path_prefix=ImgSvrMain::instance().GetConfig().img_root_path;
        string ip=ImgSvrMain::instance().GetConfig().local_ip;
        unsigned int port=ImgSvrMain::instance().GetConfig().nginx_port;
        for(vector<GeneralImgReqBodyStruct>::iterator req_body_it=_req_struct.req_body.begin();req_body_it!=_req_struct.req_body.end();req_body_it++){
            int cur_count=0;
            GenneralImgResBodyStruct res_body_temp;
            res_body_temp.res_id=req_body_it->req_id;
            for(vector<pic_store_api::ImgStruct>::const_iterator it=imgs.begin();it!=imgs.end();it++){
                if(it->uid!=req_body_it->uid){
                    continue;
                }
                string path;
                path.append("/").append(common::DateTime::CurDateStr()).append("/").append(req_body_it->busi_type).append("/").append(it->uid).append("/");
                string total_path;
                total_path.append(path_prefix).append(path);
                Poco::File f(total_path);
                f.createDirectories();
                string filename=it->snapshot_time;
                filename=common::String::ReplaceAll(filename," ","_");
                filename=common::String::ReplaceAll(filename,":","_");
                filename.append(".jpeg");
                total_path.append(filename);
                if(it->file_data.size()==0){
                    continue;
                }
                std::ofstream ofs;
                ofs.open(total_path.c_str());
                if(!ofs.is_open()){
                    continue;
                }
                ofs.write(it->file_data.c_str(),it->file_data.size());
                ofs.close();
                DownloadLog.information("save file %s size:%lu",total_path,it->file_data.size());
                string url="http://";
                url.append(ip).append(":").append(common::String::IntToString<unsigned long>(port)).append(path).append(filename);
                res_body_temp.urls.push_back(url);
                cur_count++;
            }
            res_body_temp.count=(int)res_body_temp.urls.size();
            _res_struct.res_body.push_back(res_body_temp);
        }

    }

    int GeneralImgReqHandler::GetImages(vector<pic_store_api::ImgStruct> &imgs) {
        Poco::ThreadPool thread_pool(1,4);
        Poco::Event  ev_1,ev_2,ev_3,ev_4;
        vector<pic_store_api::ImgStruct> img_1,img_2,img_3,img_4;
        vector<SharedPtr<vector<pic_store_api::ImgStruct> > > imgss;
        for(vector<pic_store_api::ImgStruct>::iterator it=imgs.begin();it!=imgs.end();it++){
            if(it->img_name.size()==52){
                string room_num=it->img_name.substr(46,2);
                if(room_num=="01"){
                    img_1.push_back(*it);
                } else if(room_num=="02"){
                    img_2.push_back(*it);
                } else if(room_num=="03"){
                    img_3.push_back(*it);
                } else if(room_num=="04"){
                    img_4.push_back(*it);
                }
            }else{
                continue;
            }
        }
        imgs.clear();
        PackPicStoreApi  api_1(ev_1,img_1),api_2(ev_2,img_2),api_3(ev_3,img_3),api_4(ev_4,img_4);
        thread_pool.start(api_1);
        thread_pool.start(api_2);
        thread_pool.start(api_3);
        thread_pool.start(api_4);
        ev_1.wait();
        for(vector<pic_store_api::ImgStruct>::iterator it=img_1.begin();it!=img_1.end();it++) {
            imgs.push_back(*it);
        }
        ev_2.wait();
        for(vector<pic_store_api::ImgStruct>::iterator it=img_2.begin();it!=img_2.end();it++) {
            imgs.push_back(*it);
        }
        ev_3.wait();
        for(vector<pic_store_api::ImgStruct>::iterator it=img_3.begin();it!=img_3.end();it++) {
            imgs.push_back(*it);
        }
        ev_4.wait();
        for(vector<pic_store_api::ImgStruct>::iterator it=img_4.begin();it!=img_4.end();it++) {
            imgs.push_back(*it);
        }
        return (int)imgs.size();
    }

    void GeneralImgReqHandler::PackResJson(string &json) {
        Poco::JSON::Object obj;
        Poco::JSON::Array array;
        std::stringstream ss;
        obj.set("staff_id",_res_struct.staff_id);
        obj.set("version",_res_struct.version);
        for(vector<GenneralImgResBodyStruct>::iterator it=_res_struct.res_body.begin();it!=_res_struct.res_body.end();it++){
            Poco::JSON::Object obj_body;
            Poco::JSON::Array url_array;
            obj_body.set("res_id",it->res_id);
            obj_body.set("count",it->count);
            for(vector<string>::iterator url_it=it->urls.begin();url_it!=it->urls.end();url_it++){
                url_array.add(*url_it);
            }
            obj_body.set("img_url",url_array);
            array.add(obj_body);
        }
        obj.set("body",array);
        // obj.set("test","test/hell");
        obj.stringify(ss);
        json=ss.str();
    }
}